/**
 * $Id: InferenceDao.java 8 2011-10-02 09:35:56Z adriftrock@gmail.com $
 */

package com.swehr.server.daos.impl;

import com.google.inject.Singleton;
import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.ontology.OntModelSpec;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.reasoner.Reasoner;
import org.apache.log4j.Logger;
import org.mindswap.pellet.jena.PelletReasonerFactory;

/**
 * @author Rock Huang
 * @version 0.1
 */
@Singleton
public class InferenceDao {
    private final static Logger log = Logger.getLogger(InferenceDao.class);
    private OntModel hrModel;
    private QueryExecution qexec = null;

    public InferenceDao() throws Exception {
        log.debug("### Initialize InferenceDao ###");
        initHrModel();
        loadData();
    }

    public void initHrModel() {
        // loading Personnel.owl as schema
        Model tbox = ModelFactory.createDefaultModel();
        tbox.read(getClass().getResourceAsStream("/Personnel.owl"), null);

        // create an empty data model
        Model abox = ModelFactory.createDefaultModel();

        // create a new Reasoner instance using the PelletReasonerFactory.
        Reasoner reasoner = PelletReasonerFactory.theInstance().create();

        // create Jena inference model using Jena ModelFactory
        Model infModel = ModelFactory.createInfModel(reasoner, tbox, abox);

        // create Jena OntModel,
        hrModel = ModelFactory.createOntologyModel(OntModelSpec.OWL_DL_MEM, infModel);
    }

    public void loadData() {
        log.debug("### loading data into inference model ###");
        StringBuffer cmd = new StringBuffer();
        ConnectDao conn = new ConnectDao();
        cmd.append("select * where { graph ?g {?o ?p ?s} }");
        try {
            conn.executeQuery(cmd.toString());
            Model dftModel = conn.getDs().getDefaultModel();
            Model orgModel = conn.getDs().getNamedModel("http://axessinfo.com/store/org");
            Model posModel = conn.getDs().getNamedModel("http://axessinfo.com/store/pos");
            Model psnModel = conn.getDs().getNamedModel("http://axessinfo.com/store/psn");
            hrModel.add(dftModel).add(orgModel).add(psnModel).add(posModel);
            hrModel.setNsPrefix("ehr", Const.NS);
        } catch (Exception e) {
            log.error(e);
            e.printStackTrace();
        } finally {
            conn.close();
        }
    }

    /**
     * To start a inference model. <br>
     * Checking 'isUpdated'. If it is true then refresh hrModel.
     *
     * @throws Exception An Exception might be thrown.
     */
    public void begin() throws Exception {
        if (hrModel == null || hrModel.isClosed()) {
            log.debug("### Reload hrModel ###");
            initHrModel();
            loadData();
        }
    }

    public ResultSet executeQuery(String sparql) throws Exception {
        qexec = QueryExecutionFactory.create(prepare(sparql), hrModel);
        return qexec.execSelect();
    }

    public void end() {
        if (qexec != null) {
            qexec.close();
        }
    }

    public QueryExecution create(String sparql) throws Exception {
        begin();
        return QueryExecutionFactory.create(prepare(sparql), hrModel);
    }

    public void add(Model model) {
        hrModel.add(model);
    }

    public OntModel getHrModel() {
        return hrModel;
    }

    private String prepare(String sparql) {
        StringBuffer cmd = new StringBuffer();
        cmd.append(Const.XSD).append("\n").append(Const.RDF).append("\n");
        cmd.append(Const.RDFS).append("\n").append(Const.EHR).append("\n");
        cmd.append(Const.DBPO).append("\n").append(Const.DBPP).append("\n");
        cmd.append(Const.OWL).append("\n").append(Const.SCHM).append("\n");
        cmd.append(sparql);
        log.debug("\n" + cmd.toString());
        return cmd.toString();
    }
}
